from tkinter import *
from tkinter import ttk
from tkinter.filedialog import askopenfilenames, askdirectory, askopenfilename
from tkinter.messagebox import askquestion, showerror
from tkinter.font import Font
from PIL import Image, ImageTk
import os

class AppGui:
    def __init__(self, ac):        
        self.root = Tk()
        self.AppCon = ac
        self.mainWindow = Frame(self.root)
        
        self.AbstractColumnList = [['Title',BooleanVar()], ['Author',BooleanVar()], ['Added date',BooleanVar()], ['Modified date',BooleanVar()], ['Read date',BooleanVar()], ['Complete',BooleanVar()]]
        self.DetailColumnList = [['Title',BooleanVar()], ['Size',BooleanVar()], ['Added date',BooleanVar()], ['Read date',BooleanVar()], ['Path',BooleanVar()]]
        self.abstract_dataCols = []
        self.detail_dataCols = []
        
        # Create menu bar
        self._create_menubar()
        
        #setting abstract&detail dataCols
        for [key, value] in self.AbstractColumnList:
            if value.get() == 1:
                self.abstract_dataCols.append(key)
        for [key, value] in self.DetailColumnList:
            if value.get() == 1:
                self.detail_dataCols.append(key)
        
        # Create the middle panel
        self.Panel = Frame(self.mainWindow)
        self.Panel.pack()
        self._create_middleview()    
        
        # Create the entry widget
        self.entry = Entry(self.mainWindow)
        self.entry.insert(0, "Hello world")
        self.entry.pack(fill=X)

        # now add the 2 buttons
        # we use a nested frame pair to give a grooved effect
        fOuter = Frame(self.mainWindow, border=1, relief="sunken")
        fButtons = Frame(fOuter, border=1, relief="raised")
        bClear = Button(fButtons, text="Clear",
                      width=8, height=1, command=self.clearText)
        bQuit = Button(fButtons, text="Quit",
                      width=8, height=1, command=self.mainWindow.quit)
        bClear.pack(side="left", padx=15, pady=1)
        bQuit.pack(side="right", padx=15, pady=1)
        fButtons.pack(fill=X)
        fOuter.pack(fill=X)
        self.mainWindow.pack()
        
        self.AppCon.setNoObjectImage()
        self._load_image()

        # set the title
        self.mainWindow.master.title("Comic Beehive")

    def quitFunc(self):
        self.mainWindow.quit()
    
    def do_abstract_tree_double_click(self, event):
        print("do abstract tree Double Click")
        selected_iid = self.abstract_tree.identify('item',event.x,event.y)
        print(selected_iid)
        pass
    
    def do_abstract_tree_selection(self, event):
        print("abstract tree selection event")
        try:
            selected_iid = self.abstract_tree.selection()[0]
            self.AppCon.AbstractTreeViewClick(selected_iid)            
            self._load_detail_data()
            print(selected_iid)
        except IndexError:
            pass
        
    def do_abstract_tree_right_click(self, event):
        print("do abstract tree right click")
        selected_iid = self.abstract_tree.identify('item',event.x,event.y)
        self.abstract_tree.selection_set(items=selected_iid)
        self.abstract_tree.popup_menu.post(event.x_root, event.y_root)
    
    def do_detail_tree_double_click(self, event):
        print('do detail tree double click')        
        try:
            selected_iid = self.detail_tree.identify('item',event.x,event.y)
            if selected_iid == '': #select column
                pass
            else:
                if self.AppCon.Honeyviewpath == '':
                    self.do_set_honeyview()
                
                self.AppCon.DetailTreeViewDoubleClick(selected_iid)
        except IndexError:
            pass
    
    def do_detail_tree_selection(self, event):
        selected_iid = self.detail_tree.selection()[0]
        print("detail tree selection event")
        try:
            print(selected_iid)
            selected_iid = self.abstract_tree.selection()[0]
            self.AppCon.DetailTreeViewClick(selected_iid)
            self._load_image()            
        except IndexError:
            pass
        
    def do_detail_tree_right_click(self, event):
        print("do detail tree right click")
        selected_iid = self.detail_tree.identify('item',event.x,event.y)
        self.detail_tree.selection_set(items=selected_iid)
        self.detail_tree.popup_menu.post(event.x_root, event.y_root)
    
    def do_new_files(self):
        filetypes = [('zip files','*.zip *.alz *.rar *.7z'), ("All files", "*.*")]
        self.AppCon.getFiles(askopenfilenames(filetypes=filetypes))
        self.do_refresh()
    
    def do_new_folder(self):
        self.AppCon.getFolder(askdirectory())
        self.do_refresh()
        
    def do_refresh(self):
        self.AppCon.refresh()
        self._load_data()       
        
    def do_set_honeyview(self):
        askresult = askquestion(title = "ask", message = "Do you want to find automatically huneyview file?")
        
        if askresult == "yes":
            result = self.AppCon.sethoneyviewpath()
        else:
            filetypes = [('Honeyview executable file', 'Honeyview.exe')]
            result = self.AppCon.sethoneyviewpath(askopenfilename(filetypes = filetypes))
            
        
        if result == "setting":
            pass
        elif result == "cannot_find_auto":
            self.AppCon.sethoneyviewpath(askopenfilename(filetypes = filetypes))
        elif result == "error":
            showerror(title = "Honeyview path setting error", message = "There are some system error! \nPlease again.")
            
    def clearText(self):
        self.entry.delete(0, END)
        
    def _create_popupmenu(self):
        #create abstract tree popup menu
        self.abstract_tree.popup_menu = Menu(self.abstract_tree, tearoff=0)
        self.abstract_tree.popup_menu.add_command(label="AAA", command=self.dummyfunc)
        self.abstract_tree.popup_menu.add_command(label="BBB", command=self.dummyfunc)
        #create detail tree popup menu
        self.detail_tree.popup_menu = Menu(self.detail_tree, tearoff=0)
        self.detail_tree.popup_menu.add_command(label="CCC", command=self.dummyfunc)
        self.detail_tree.popup_menu.add_command(label="DDD", command=self.dummyfunc)
        
    def _create_menubar(self):
        # set the menu bar
        menubar = Menu(self.mainWindow)
        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label="new files", command=self.do_new_files)
        filemenu.add_command(label="new folder", command=self.do_new_folder)
        filemenu.add_separator()
        filemenu.add_command(label="refresh", command=self.do_refresh)
        filemenu.add_separator()
        filemenu.add_command(label="Quit", command=self.quitFunc)
        menubar.add_cascade(label="File", menu=filemenu)
        
        #make column setting menu
        self.AbstractColumnList[0][1].set(1)
        self.AbstractColumnList[1][1].set(1)
        self.AbstractColumnList[2][1].set(1)
        self.DetailColumnList[0][1].set(1)
        self.DetailColumnList[1][1].set(1)
        self.DetailColumnList[4][1].set(1)
                
        for [key, value] in self.AbstractColumnList:
            value.trace('w', self.AbstractColumnSetting)
        for [key, value] in self.DetailColumnList:
            value.trace('w', self.DetailColumnSetting)
        
        columnmenu = Menu(menubar, tearoff=0)
        abstractcolumnmenu = Menu(columnmenu)
        for [key, value] in self.AbstractColumnList:
            abstractcolumnmenu.add_checkbutton(label=key, variable=value, onvalue=True, offvalue=False)
        columnmenu.add_cascade(label='Comic Column', menu=abstractcolumnmenu)        
        
        columnmenu.add_separator()
        
        detailcolumnmenu = Menu(columnmenu)
        for [key, value] in self.DetailColumnList:
            detailcolumnmenu.add_checkbutton(label=key, variable=value, onvalue=True, offvalue=False)
        columnmenu.add_cascade(label='Book Column', menu=detailcolumnmenu)
        menubar.add_cascade(label='Column View', menu = columnmenu)
        
        #make setting menu
        settingmenu = Menu(menubar, tearoff=0)
        settingmenu.add_command(label = "Set HoneyView", command=self.do_set_honeyview)
        menubar.add_cascade(label = "Setting", menu = settingmenu)
         
        self.root.config(menu=menubar)
        
    def _create_middleview(self):
        parent = self.Panel        
        self.middleFrame = ttk.Frame(parent)
        f = self.middleFrame
        f.pack(side=TOP, fill=BOTH, expand=Y)
        
        # abstract tree making 
        # create the tree and scrollbars               
        self.abstract_tree = ttk.Treeview(columns=self.abstract_dataCols, show = 'headings', selectmode='browse')
         
        ysb = ttk.Scrollbar(orient=VERTICAL, command= self.abstract_tree.yview)
        xsb = ttk.Scrollbar(orient=HORIZONTAL, command= self.abstract_tree.xview)
        self.abstract_tree['yscroll'] = ysb.set
        self.abstract_tree['xscroll'] = xsb.set
         
        # add tree and scrollbars to frame
        self.abstract_tree.grid(in_=f, row=0, column=0, sticky=NSEW)
        ysb.grid(in_=f, row=0, column=1, sticky=NS)
        xsb.grid(in_=f, row=1, column=0, sticky=EW)
                
        # detail tree making
        # create the tree and scrollbars           
        self.detail_tree = ttk.Treeview(columns=self.detail_dataCols, show = 'headings', selectmode='browse')
         
        ysb2 = ttk.Scrollbar(orient=VERTICAL, command= self.detail_tree.yview)
        xsb2 = ttk.Scrollbar(orient=HORIZONTAL, command= self.detail_tree.xview)
        self.detail_tree['yscroll'] = ysb2.set
        self.detail_tree['xscroll'] = xsb2.set
         
        # add tree and scrollbars to frame
        self.detail_tree.grid(in_=f, row=0, column=2, sticky=NSEW)
        ysb2.grid(in_=f, row=0, column=3, sticky=NS)
        xsb2.grid(in_=f, row=1, column=2, sticky=EW)
        
        # set frame resize priorities
        f.rowconfigure(0, weight=1)
        f.columnconfigure(0, weight=1)
        
        self.abstract_tree.bind("<Double-1>", self.do_abstract_tree_double_click)
        self.abstract_tree.bind("<<TreeviewSelect>>", self.do_abstract_tree_selection)
        self.abstract_tree.bind("<Button-3>", self.do_abstract_tree_right_click)
        self.detail_tree.bind("<Double-1>", self.do_detail_tree_double_click)
        self.detail_tree.bind("<<TreeviewSelect>>", self.do_detail_tree_selection)
        self.detail_tree.bind("<Button-3>", self.do_detail_tree_right_click)
        
        self.abstract_tree.SortDir = False
        self.detail_tree.SortDir = False
        
        self._load_data()
        
        self._create_popupmenu()
         
        #information panel making
        self.info_panel = Frame(f)
        self.info_panel.grid(in_=f, row=0, column=4, sticky=NSEW)       
        temp_label = Label(self.info_panel, text="hi hello")
        temp_label.pack()
        self.info_panel.image_label = Label(self.info_panel)    
        pass 
    
    def _load_image(self):
        self.info_panel.image_label.destroy()
        self.info_panel.image_label = Label(self.info_panel, width = 200, height = 200, image=self.AppCon.LabelImage)            
        self.info_panel.image_label.image = self.AppCon.LabelImage
        self.info_panel.image_label.pack()        
        pass        
        
    def _load_data(self):
        self._load_abstract_data()
        self._load_detail_data()
         
    def _load_abstract_data(self):
        # configure column headings
        
        print(self.abstract_dataCols)              
        for c in self.abstract_dataCols:
            self.abstract_tree.heading(c, text=c.title(), command=lambda c=c: self._column_sort(self.abstract_tree, c))           
            self.abstract_tree.column(c, width=Font().measure(c.title()))            
        
        #clear list before add data
        for item in self.abstract_tree.get_children():
            self.abstract_tree.delete(item)
            
        # add data to the tree        
        for item in self.AppCon.abstract_list:
            temp_item = []
            for c in self.abstract_dataCols:
                temp_item.append(item[c])            
            item_iid = self.abstract_tree.insert('', 'end', values=temp_item)
            item['iid'] = item_iid
            
             
            # and adjust column widths if necessary
            for idx, val in enumerate(temp_item):
                iwidth = Font().measure(val)
                if self.abstract_tree.column(self.abstract_dataCols[idx], 'width') < iwidth:
                    self.abstract_tree.column(self.abstract_dataCols[idx], width = iwidth)
        
        All_item = []
        for c in self.abstract_dataCols:
            All_item.append('All')
        self.abstract_tree.insert('', 0, iid='All', values=All_item)

    def _load_detail_data(self):
        # configure column headings
        for c in self.detail_dataCols:
            self.detail_tree.heading(c, text=c.title(),
                              command=lambda c=c: self._column_sort(self.detail_tree, c))           
            self.detail_tree.column(c, width=Font().measure(c.title()))
        
        #clear list before add data
        for item in self.detail_tree.get_children():
            self.detail_tree.delete(item)
            
        # add data to the tree        
        for item in self.AppCon.detail_list:
            temp_item = []
            for c in self.detail_dataCols:
                temp_item.append(item[c])            
            item_iid = self.detail_tree.insert('', 'end', values=temp_item)
            item['iid'] = item_iid
             
            # and adjust column widths if necessary
            for idx, val in enumerate(temp_item):
                iwidth = Font().measure(val)
                if self.detail_tree.column(self.detail_dataCols[idx], 'width') < iwidth:
                    self.detail_tree.column(self.detail_dataCols[idx], width = iwidth)

    def _column_sort(self, tree, col):
         
        # grab values to sort as a list of tuples (column value, column id)
        # e.g. [('Argentina', 'I001'), ('Australia', 'I002'), ('Brazil', 'I003')]
        data = [(tree.set(child, col), child) for child in tree.get_children('')]
         
        # reorder data
        # tkinter looks after moving other items in
        # the same row
        data.sort(reverse=tree.SortDir)
        for indx, item in enumerate(data):
            tree.move(item[1], '', indx)   # item[1] = item Identifier
         
        # reverse sort direction for next sort operation
        tree.SortDir = not tree.SortDir
        
        #All item should be first in abstract tree view
        if tree.exists('All'):
            tree.move('All', '', 0)
        
    
    def AbstractColumnSetting(self, *args):
        print('abstract column setting')
        self.abstract_dataCols = []
        for [key, value] in self.AbstractColumnList:
            if value.get() == 1:
                self.abstract_dataCols.append(key)
        self.middleFrame.destroy()
        self._create_middleview()
        
        
    def DetailColumnSetting(self, *args):
        print('detail column setting')
        self.detail_dataCols = []
        for [key, value] in self.DetailColumnList:
            if value.get() == 1:
                self.detail_dataCols.append(key)
        self.middleFrame.destroy()
        self._create_middleview()
    
    def dummyfunc(self):
        print("dummy")